from gameServer import gameServer
from object import Object
from vec2 import Vec2
from vec3 import Vec3
from eventServer import eventServer
from collisionServer import collisionServer
from soundServer import sound
from cube import Cube
from cCube import CCube
from movingPlatform import MovingPlatform
from humanCube import HumanCube
from items.carryCube import CarryCube
from items.collectCube import CollectCube
from items.gun import Gun
from items.extraFast import ExtraFast
from items.spikeHat import SpikeHat
from flipBlock import FlipBlock
from itemGun import ItemGun
from gameRules import GameRules
from copy import copy
from aiCube import AICube
from dynLoad import dynLoad
from random import Random

import math
import random

class Level(Object):
    def __init__(self):
        Object.__init__(self)
        
        self.defaultVar("backgroundTexture","")
        self.defaultVar("spawnBoxSize",0.8)
        self.defaultVar("spawnTime",4.0)
        self.spawnPlayers = {}
        self.time = 0
        
        eventServer.register("startLevel",self.startLevel)
        eventServer.register("stopLevel",self.stopLevel)
        eventServer.register('spawnPlayer',self.spawnPlayer)
        eventServer.register('despawnPlayer',self.despawnPlayer)
        eventServer.register('update',self.update)
        eventServer.register('spawnItem',self.spawnItem)
        
    def startLevel(self, cmd, args):
        #print cmd, args
        sound.play("game" + str(random.randint(1, 3)), True)
        if args.has_key('filename'):
            filename = args['filename']
        elif args.has_key('spinner_level'):
            filename = args['spinner_level'] + ".yml"
        else:
            filename = ''
            
        if args.has_key('numPlayers'):
            numPlayers = args['numPlayers']
        elif args.has_key('spinner_players'):
            numPlayers = args['spinner_players']
        else:
            numPlayers = 1
        self.setVar("numPlayers",numPlayers)
            
        if args.has_key('gameMode'):
            gameMode = args['gameMode']
        elif args.has_key('spinner_gameMode'):
            gameMode = args['spinner_gameMode'] + ".yml"
        else:
            gameMode = ''
            
        print "loading game mode", gameMode
        gameRules = gameServer.addObject('gameRules',GameRules())
        gameRules.setVar("numPlayers",numPlayers)
        gameRules.setVar("aiType","nearestAttack")
        gameRules.load(gameMode)
        
        print "loading filename", filename
        self.load(filename)
        
        self.cubes = []
        
        if self.vars.has_key('cubes'):
            
            minx = maxx = miny = maxy = None
            posTot = Vec3()
            numCubes = 0
            
            for cubeName, vals in self.vars['cubes'].iteritems():
                if gameServer.hasObject(cubeName):
                    cubeName = gameServer.makeObjectName(cubeName)
                    
                x = y = 0
                w = h = d = tiles = 1
                texture = ""
                
                if vals.has_key('size'):
                    size = vals['size']
                    if type(size) != tuple or len(size) < 2 or len(size) > 3:
                        print "invalid size value in file %s" % filename, size
                    elif len(size) == 2:
                        w,h = size
                    else:
                        w,h,d = size
                        
                if vals.has_key('x'):
                    x = vals['x']
                if vals.has_key('y'):
                    y = vals['y']
                if vals.has_key('w'):
                    w = vals['w']
                if vals.has_key('h'):
                    h = vals['h']
                if vals.has_key('d'):
                    d = vals['d']
                if vals.has_key('texture'):
                    texture = vals['texture']
                if vals.has_key('tiles'):
                    tiles = vals['tiles']
                    
                if vals.has_key('base'):
                    base = vals['base']
                else:
                    base = 'cCube'
                    
                if(base == 'cube'):
                    cube = gameServer.addObject(cubeName,Cube())
                elif(base == 'movingPlatform'):
                    cube = gameServer.addObject(cubeName,MovingPlatform())
                    if vals.has_key('pos'):
                        home  = vals['pos']
                        homeV = Vec2(home[0]+w/2.0, home[1]+h/2.0)
                        cube.setVar("home", homeV)
                        if type(home) != tuple or len(home) != 2:
                            print "invalid pos value in file %s:" % filename, home
                            
                    if vals.has_key('vel'):
                        vel  = vals['vel']
                        velV = Vec2(vel[0], vel[1])
                        cube.setVar("vel", velV)
                        if type(vel) != tuple or len(vel) != 2:
                            print "invalid pos value in file %s:" % filename, vel
                            
                    if vals.has_key('range'):
                        cube.setVar('range', vals['range'])
                elif(base == 'carryCube'):
                    cube = gameServer.addObject(cubeName,CarryCube())
                elif(base == 'collectCube'):
                    cube = gameServer.addObject(cubeName,CollectCube())
                elif(base == 'gun'):
                    cube = gameServer.addObject(cubeName,Gun())
                elif(base == 'extraFast'):
                    cube = gameServer.addObject(cubeName,ExtraFast())
                elif(base == 'spikeHat'):
                    cube = gameServer.addObject(cubeName,SpikeHat())
                elif(base == 'flipBlock'):
                    cube = gameServer.addObject(cubeName,FlipBlock())
                    if vals.has_key('flipTime'):
                        cube.setVar('flipTime', vals['flipTime'])
                elif(base == 'itemGun'):
                    cube = gameServer.addObject(cubeName,ItemGun())
                else:
                    cube = gameServer.addObject(cubeName,CCube())
                   
                #print cubeName, vals
                
                if vals.has_key('pos'):
                    pos = vals['pos']
                    if type(pos) != tuple or len(pos) != 2:
                        print "invalid pos value in file %s:" % filename, pos
                    else:
                        x,y = pos
               
                if vals.has_key('rot'):
                    rot = math.radians(vals['rot'])
                else:
                    rot = 0
                
                if(not(cube.hasVar("sides"))):
                    cube.setVar("sides",['s','s','s','s'])
                    
                sides = cube.getVar("sides")
                if vals.has_key('side0'):
                    sides[0] = vals['side0']
                if vals.has_key('side1'):
                    sides[1] = vals['side1']
                if vals.has_key('side2'):
                    sides[2] = vals['side2']
                if vals.has_key('side3'):
                    sides[3] = vals['side3']

                pos = Vec3(x+w/2.0,y+h/2.0,0)
                posTot += pos
                numCubes += 1
                if not minx or pos.x < minx:
                    minx = pos.x
                if not maxx or pos.x > maxx:
                    maxx = pos.x
                if not miny or pos.y < miny:
                    miny = pos.y
                if not maxy or pos.y > maxy:
                    maxy = pos.y
                    
                cube.setVar("pos",pos)
                cube.setVar("rot",rot)
                cube.setVar("scale",Vec3(w,h,d))
                cube.setVar("texture",texture)
                cube.setVar("tiles",tiles)
                
                #print cubeName, cube.getVar("pos"), cube.getVar("scale"), cube.getVar("texture")
                
                self.cubes.append(cubeName)
                
            if numCubes:
                #avePos = posTot / float(numCubes)
                avePos = Vec3((minx + maxx) / 2.0, (miny + maxy) / 2.0, 0)
                width = maxx - minx + 1
                height = maxy - miny + 1
                self.setVar("center",avePos)
                self.setVar("width",width)
                self.setVar("height",height)
                print "level center", avePos, "size", width
                collisionServer.initialize(width,pos.x,pos.y)
                
                camera = gameServer.getObject("camera")
                if camera:
                    camera.setVar("lookAt",avePos)
                    camera.setVar("dist",max(width,height))
                    camera.setVar("numPlayers",numPlayers)
                
        print "numPlayers", numPlayers
        
        self.players = []
        for i in range(numPlayers):
            playerName = 'player%d' % i
            
            typeName = 'spinner_player%dPlayer' % i
            if args.has_key(typeName):
                playerType = args[typeName]
            else:
                playerType = 'player'
                
            if playerType == 'human':
                player = gameServer.addObject(playerName, HumanCube(i))
            else:
                aiClass = dynLoad(gameRules.getVar("aiType"),folderName="bots") or AICube
                #print "AI class", gameRules.getVar("aiType"), aiClass
                player = gameServer.addObject(playerName,aiClass(i))
            
            #player = gameServer.addObject(playerName, HumanCube(i))
            player.setVar("dead",True)
            player.setVar("score",0)
            
            textureName = 'spinner_player%dTexture' % i
            if args.has_key(textureName):
                player.setVar("texture",args[textureName] + '/Sprite_Stand1')
                player.setVar("animationFamily",args[textureName])
                player.setVar("animation","Stand")
            
            self.players.append(playerName)
            
            #eventServer.pull('despawnPlayer',{'player':i})
            
        bgTexture = self.getVar("backgroundTexture")
        print "background", bgTexture
        if bgTexture:
            if self.hasVar("backgroundx") and self.hasVar("backgroundy"):
                pos = Vec3(self.getVar("backgroundx"),self.getVar("backgroundy"),-5)
            else:
                pos = self.getVar("center") + Vec3(0,0,-5)
            
            if self.hasVar("backgroundWidth"):
                w = self.getVar("backgroundWidth")
            else:
                w = self.getVar("width") * 2.0
                
            if self.hasVar("backgroundHeight"):
                h = self.getVar("backgroundHeight")
            else:
                h = self.getVar("height") * 1.5
                
            scale = Vec3(w,h,1)
            bgCube = gameServer.addObject("background",Cube())
            bgCube.setVar("texture",bgTexture)
            bgCube.setVar("pos",pos)
            bgCube.setVar("scale",scale)
            
            if self.hasVar("backgroundTiles"):
                bgCube.setVar("tiles",self.getVar("backgroundTiles"))
            
        print "startRound"
        eventServer.pull('startRound',{'numPlayers':numPlayers})
        print "/startRound"
        
    def update(self, cmd, args):
        self.time = args['time']
        
        toRemove = []
        for player, (time, pos) in self.spawnPlayers.iteritems():
            #print player, self.time - time, self.getVar("spawnTime")
            if self.time - time > self.getVar("spawnTime"):
                self.doSpawnPlayer(player,pos)
                toRemove.append(player)
                
        for player in toRemove:
            self.spawnPlayers.pop(player)
            #print "remove", player, self.spawnPlayers
    
    def spawnPlayer(self, cmd, args):
        player = args['player']
        playerName = 'player%d' % player
        playerObj = gameServer.getObject(playerName)
        if playerObj and playerObj.getVar("dead"):
            texture = playerObj.getVar("texture")
            pos = self.makePlayerPos()
            lifetime = self.getVar("spawnTime")
            eventServer.pull('makeParticleEffect',{'pos':pos,"texture":texture,"moveOut":False,"minLifetime":lifetime,"maxLifetime":lifetime})
            self.spawnPlayers[player] = (copy(self.time),pos)
            #print "add", player, self.spawnPlayers
            
    def doSpawnPlayer(self, player, pos):
        playerName = 'player%d' % player
        player = gameServer.getObject(playerName)
        print "spawn", playerName
        if player and player.getVar("dead"):
            player.setVar("dead",False)
            player.setVar("shown",True)
            #pos = self.makePlayerPos()
            player.setVar("pos",pos)
            player.resetPhysics()
            
            texture = player.getVar("texture")
            
            
    def despawnPlayer(self, cmd, args):
        playerName = 'player%d' % args['player']
        player = gameServer.getObject(playerName)
        print "despawn", playerName
        if player and not player.getVar("dead"):
            player.setVar("dead",True)
            player.setVar("shown",False)
            pos = player.getVar("pos")
            player.setVar("pos",Vec3(10000,0,10000))
            eventServer.pull('itemCollected',{'player':args['player'],'collected':None})
            eventServer.pull("itemDropped",{"player":args['player']})
           
            texture = player.getVar("texture")
            eventServer.pull("makeParticleEffect",{'pos':pos,'texture':texture})
            
    def makePlayerPos(self):
        center = self.getVar("center")
        size = self.getVar("spawnBoxSize")
        w = self.getVar("width") * size
        h = self.getVar("height") * size
        x = random.uniform(center.x-w/2.0,center.x+w/2.0)
        y = random.uniform(center.y-h/2.0,center.y+h/2.0)
        return Vec3(x,y,center.z)
                
    def stopLevel(self, cmd, args):
        sound.stop("game")
        for cubeName in self.cubes:
            gameServer.removeObject(cubeName)
            
        for playerName in self.players:
            gameServer.removeObject(playerName)
            
        gameServer.removeObject('gameRules')
        gameServer.removeObject("background")
            
        collisionServer.clear()
        
    def spawnItem(self, cmd, args):
        if args.has_key('type'):
            type = args['type']
        else:
            type = 'spikeHat'
            
        if args.has_key('name'):
            name = args['name']
        else:
            name = type
            
        if args.has_key('pos'):
            pos = args['pos']
        else:
            pos = self.makePlayerPos()
            
        if gameServer.hasObject(name):
            name = gameServer.makeObjectName(name)
            
        item = gameServer.addObject(name,(dynLoad(type,folderName='items') or CarryCube)())
        item.setVar('pos',pos)
        
